ggthemes
First let’s look at a simple scatterplot made by geom_point() and with no themes:
p <- ggplot(mtcars, aes(x = wt, y = mpg)) +
geom_point() +
ggtitle("Cars")
p

Cool, we can add a title. More generally, we can modify labels for the plot, axes, and legends by using labs:
p2 <- ggplot(mtcars, aes(x = wt, y = mpg, color = factor(gear))) +
geom_point() +
labs(title = "Feul Efficiency of Cars", subtitle="(derived from data originally found in the mtcars dataset)", x="Weight", y="Miles per Gallon", color = "Gear", caption="This plot displays how the fuel efficiency of vehicles in the dataset scales with their weight.")
p2

Tufte theme and geoms
Minimal theme and geoms based on plots in The Visual Display of Quantitative Information.
p + geom_rangeframe() +
theme_tufte()

Economist theme
A theme that approximates the style of plots in The Economist magazine.
p + theme_economist() + scale_colour_economist()

Excel 2003 theme
For that classic ugly look and feel
p2 + theme_excel() + scale_colour_excel()

Wall Street Journal
Theme and some color palettes based on plots in the The Wall Street Journal.
p2 + theme_wsj() + scale_colour_wsj("colors6", "")

Template for layered grammar of graphics
ggplot(data = <DATA>) +
<GEOM_FUNCTION>(
mapping = aes(<MAPPINGS>),
stat = <STAT>,
position = <POSITION>
) +
<COORDINATE_FUNCTION> +
<FACET_FUNCTION>
In practice, you rarely need to supply all seven parameters to make a graph because ggplot2 will provide useful defaults for everything except the data, the mappings, and the geom function.
More Examples
Bar Chart from Top 50 ggplot2 Visualizations.
We saw how to create a bar chart with geom_bar(). By default geom_bar() will use stat = "count", so we don’t need to provide a y, it’s being calculated as the count of points in each bin. In order to create a bar chart with a given y value we need to set stat=identity and provide both x and y inside aes() x is either character or factor and y is numeric.
# create a frequency table
freqtable <- table(mpg$manufacturer)
df <- as.data.frame.table(freqtable)
head(df)
ggplot(df, aes(Var1, Freq)) +
geom_bar(stat="identity", width = 0.5, fill="tomato2") +
labs(title="Bar Chart",
subtitle="Manufacturer of vehicles",
caption="Source: Frequency of Manufacturers from 'mpg' dataset",
x = "Manufacturer") +
theme_classic() +
theme(axis.text.x = element_text(angle=65, vjust=0.6)) # to give x labels an angle for readability
Email Campaign Funnel from Top 50 ggplot2 Visualizations:
options(scipen = 999) # turns off scientific notations like 1e+40
options(repr.plot.width=7, repr.plot.height=5) # Modifying the chart size
# Read data
options(readr.num_columns = 0) # turns off messages printed by read_csv
email_campaign_funnel <- read_csv("https://raw.githubusercontent.com/selva86/datasets/master/email_campaign_funnel.csv")
# X Axis Breaks and Labels
brks <- seq(-15000000, 15000000, 5000000)
lbls = paste0(as.character(c(seq(15, 0, -5), seq(5, 15, 5))), "m")
# Plot
ggplot(email_campaign_funnel, aes(x = Stage, y = Users, fill = Gender)) + # Fill column
geom_bar(stat = "identity", width = .6) + # draw the bars
scale_y_continuous(breaks = brks, # Breaks
labels = lbls) + # Labels
coord_flip() + # Flip axes
labs(title = "Email Campaign Funnel") +
theme_tufte() + # Tufte theme from ggfortify
theme(plot.title = element_text(hjust = .5),
axis.ticks = element_blank()) # Centre plot title

Line chart
dtemp <- data.frame(months = factor(rep(substr(month.name,1,3), 4), levels = substr(month.name,1,3)),
city = rep(c("Tokyo", "New York", "Berlin", "London"), each = 12),
temp = c(7.0, 6.9, 9.5, 14.5, 18.2, 21.5, 25.2, 26.5, 23.3, 18.3, 13.9, 9.6,
-0.2, 0.8, 5.7, 11.3, 17.0, 22.0, 24.8, 24.1, 20.1, 14.1, 8.6, 2.5,
-0.9, 0.6, 3.5, 8.4, 13.5, 17.0, 18.6, 17.9, 14.3, 9.0, 3.9, 1.0,
3.9, 4.2, 5.7, 8.5, 11.9, 15.2, 17.0, 16.6, 14.2, 10.3, 6.6, 4.8))
temp <- ggplot(dtemp, aes(x = months, y = temp, group = city, color = city)) +
geom_line() +
geom_point(size = 1.1) +
ggtitle("Monthly Average Temperature") +
theme_hc(style = "darkunica") +
scale_fill_hc("darkunica")
temp

Interactive plotting with Plotly
We can use package plotly on top of a ggplot plot to create interactive charts. Plotly is a powerful tool for creating interactive dashboards and plots and there are different ways to use it. Here we will only show how to make ggplots into a plotly by using ggplotly() function. For more information about other ways to leverage this package go to ploy.ly.
Scatterplot
Let’s use the most recent plot we created with WSJ theme as an example:
ggplotly(p2 + theme_wsj() + scale_colour_wsj("colors6", "")) # Same plot with ggplotly()
Time Series
Using geom_line(), a time series (or line chart) can be drawn. Data: economics from ggplot2.
head(economics)
ts_plot <- ggplot(economics, aes(x=date)) +
geom_line(aes(y=psavert)) +
labs(title="US economic time series",
subtitle = "Personal Savings Rate",
caption="Source: Economics",
y="Savings Rate %") +
theme_classic()
ggplotly(ts_plot) # Same plot with ggplotly()
Bar chart
bar_plot <- ggplot(data = diamonds) +
geom_bar(mapping = aes(x = cut, fill = clarity), position = "dodge") +
scale_fill_manual(values = c("#41f4f4", "#41d9f4", "#41bbf4", "#418ef4", "#415ef4", "#6a41f4", "#9741f4", "#f441f1"))
ggplotly(bar_plot) # Same plot with ggplotly()
LS0tDQp0aXRsZTogIlRoZW1lIg0Kc3VidGl0bGU6ICJEYXRhIFZpc3VhbGl6YXRpb24gLSBQYXJ0IDciDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQpgYGB7ciBpbmNsdWRlPUZBTFNFfQ0KIyBsb2FkaW5nIGxpYnJhcmllcw0KbGlicmFyeSh0aWR5dmVyc2UpDQpsaWJyYXJ5KGdndGhlbWVzKQ0KbGlicmFyeShwbG90bHkpDQoNCiMgbW9kaWZ5aW5nIGNoYXJ0IHNpemUNCm9wdGlvbnMocmVwci5wbG90LndpZHRoPTUsIHJlcHIucGxvdC5oZWlnaHQ9MykNCmBgYA0KDQo8Y2VudGVyPiAhW10oLi4vcG5nL2xheWVycy1vZi1nZ3Bsb3QucG5nKXt3aWR0aD00MDB9IDwvY2VudGVyPg0KDQojIyMgZ2d0aGVtZXMNCkZpcnN0IGxldCdzIGxvb2sgYXQgYSBzaW1wbGUgc2NhdHRlcnBsb3QgbWFkZSBieSBgZ2VvbV9wb2ludCgpYCBhbmQgd2l0aCBubyB0aGVtZXM6DQoNCmBgYHtyfQ0KcCA8LSBnZ3Bsb3QobXRjYXJzLCBhZXMoeCA9IHd0LCB5ID0gbXBnKSkgKw0KICBnZW9tX3BvaW50KCkgKw0KICBnZ3RpdGxlKCJDYXJzIikNCnANCmBgYA0KQ29vbCwgd2UgY2FuIGFkZCBhIHRpdGxlLiBNb3JlIGdlbmVyYWxseSwgd2UgY2FuIG1vZGlmeSBsYWJlbHMgZm9yIHRoZSBwbG90LCBheGVzLCBhbmQgbGVnZW5kcyBieSB1c2luZyBgbGFic2A6DQpgYGB7cn0NCnAyIDwtIGdncGxvdChtdGNhcnMsIGFlcyh4ID0gd3QsIHkgPSBtcGcsIGNvbG9yID0gZmFjdG9yKGdlYXIpKSkgKw0KICBnZW9tX3BvaW50KCkgKw0KICBsYWJzKHRpdGxlID0gIkZldWwgRWZmaWNpZW5jeSBvZiBDYXJzIiwgc3VidGl0bGU9IihkZXJpdmVkIGZyb20gZGF0YSBvcmlnaW5hbGx5IGZvdW5kIGluIHRoZSBtdGNhcnMgZGF0YXNldCkiLCB4PSJXZWlnaHQiLCB5PSJNaWxlcyBwZXIgR2FsbG9uIiwgY29sb3IgPSAiR2VhciIsIGNhcHRpb249IlRoaXMgcGxvdCBkaXNwbGF5cyBob3cgdGhlIGZ1ZWwgZWZmaWNpZW5jeSBvZiB2ZWhpY2xlcyBpbiB0aGUgZGF0YXNldCBzY2FsZXMgd2l0aCB0aGVpciB3ZWlnaHQuIikNCnAyDQpgYGANCg0KDQojIyMjIFR1ZnRlIHRoZW1lIGFuZCBnZW9tcw0KTWluaW1hbCB0aGVtZSBhbmQgZ2VvbXMgYmFzZWQgb24gcGxvdHMgaW4gVGhlIFZpc3VhbCBEaXNwbGF5IG9mIFF1YW50aXRhdGl2ZSBJbmZvcm1hdGlvbi4NCg0KYGBge3J9DQpwICsgZ2VvbV9yYW5nZWZyYW1lKCkgKw0KICB0aGVtZV90dWZ0ZSgpDQpgYGANCg0KIyMjIyBFY29ub21pc3QgdGhlbWUNCkEgdGhlbWUgdGhhdCBhcHByb3hpbWF0ZXMgdGhlIHN0eWxlIG9mIHBsb3RzIGluIFRoZSBFY29ub21pc3QgbWFnYXppbmUuDQoNCmBgYHtyfQ0KcCArIHRoZW1lX2Vjb25vbWlzdCgpICsgc2NhbGVfY29sb3VyX2Vjb25vbWlzdCgpIA0KYGBgDQoNCiMjIyMgRXhjZWwgMjAwMyB0aGVtZQ0KRm9yIHRoYXQgY2xhc3NpYyB1Z2x5IGxvb2sgYW5kIGZlZWwNCg0KYGBge3J9DQpwMiArIHRoZW1lX2V4Y2VsKCkgKyBzY2FsZV9jb2xvdXJfZXhjZWwoKQ0KYGBgDQoNCiMjIyMgV2FsbCBTdHJlZXQgSm91cm5hbA0KVGhlbWUgYW5kIHNvbWUgY29sb3IgcGFsZXR0ZXMgYmFzZWQgb24gcGxvdHMgaW4gdGhlIFRoZSBXYWxsIFN0cmVldCBKb3VybmFsLg0KDQpgYGB7cn0NCnAyICsgdGhlbWVfd3NqKCkgKyBzY2FsZV9jb2xvdXJfd3NqKCJjb2xvcnM2IiwgIiIpDQpgYGANCg0KIyMjIENyZWF0ZSB5b3VyIG93biB0aGVtZQ0KDQpgYGB7cn0NCmJsYW5rX3RoZW1lIDwtIHRoZW1lX21pbmltYWwoKSArDQogIHRoZW1lKA0KICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X2JsYW5rKCksDQogICAgcGFuZWwuZ3JpZCA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemU9MTQsIGZhY2U9ImJvbGQiKQ0KICAgICkNCmBgYA0KDQpgYGB7cn0NCnAgKyBibGFua190aGVtZQ0KYGBgDQoNCg0KIyMgVGVtcGxhdGUgZm9yIGxheWVyZWQgZ3JhbW1hciBvZiBncmFwaGljcw0KDQoNCmBgYA0KZ2dwbG90KGRhdGEgPSA8REFUQT4pICsgDQogIDxHRU9NX0ZVTkNUSU9OPigNCiAgICAgbWFwcGluZyA9IGFlcyg8TUFQUElOR1M+KSwNCiAgICAgc3RhdCA9IDxTVEFUPiwgDQogICAgIHBvc2l0aW9uID0gPFBPU0lUSU9OPg0KICApICsNCiAgPENPT1JESU5BVEVfRlVOQ1RJT04+ICsNCiAgPEZBQ0VUX0ZVTkNUSU9OPg0KYGBgDQoNCkluIHByYWN0aWNlLCB5b3UgcmFyZWx5IG5lZWQgdG8gc3VwcGx5IGFsbCBzZXZlbiBwYXJhbWV0ZXJzIHRvIG1ha2UgYSBncmFwaCBiZWNhdXNlIGdncGxvdDIgd2lsbCBwcm92aWRlIHVzZWZ1bCBkZWZhdWx0cyBmb3IgZXZlcnl0aGluZyBleGNlcHQgdGhlIGRhdGEsIHRoZSBtYXBwaW5ncywgYW5kIHRoZSBnZW9tIGZ1bmN0aW9uLg0KDQotLS0tDQoNCiMjIE1vcmUgRXhhbXBsZXMNCg0KKipCYXIgQ2hhcnQqKiBmcm9tIFtUb3AgNTAgZ2dwbG90MiBWaXN1YWxpemF0aW9uc10oaHR0cDovL3Itc3RhdGlzdGljcy5jby9Ub3A1MC1HZ3Bsb3QyLVZpc3VhbGl6YXRpb25zLU1hc3Rlckxpc3QtUi1Db2RlLmh0bWwpLg0KDQpXZSBzYXcgaG93IHRvIGNyZWF0ZSBhIGJhciBjaGFydCB3aXRoIGBnZW9tX2JhcigpYC4gQnkgZGVmYXVsdCBgZ2VvbV9iYXIoKWAgd2lsbCB1c2UgYHN0YXQgPSAiY291bnQiYCwgc28gd2UgZG9uJ3QgbmVlZCB0byBwcm92aWRlIGEgYHlgLCBpdCdzIGJlaW5nIGNhbGN1bGF0ZWQgYXMgdGhlIGNvdW50IG9mIHBvaW50cyBpbiBlYWNoIGJpbi4gSW4gb3JkZXIgdG8gY3JlYXRlIGEgYmFyIGNoYXJ0IHdpdGggYSBnaXZlbiBgeWAgdmFsdWUgd2UgbmVlZCB0byBzZXQgYHN0YXQ9aWRlbnRpdHlgIGFuZCBwcm92aWRlIGJvdGggYHhgIGFuZCBgeWAgaW5zaWRlIGBhZXMoKWAgYHhgIGlzIGVpdGhlciBjaGFyYWN0ZXIgb3IgZmFjdG9yIGFuZCBgeWAgaXMgbnVtZXJpYy4NCg0KYGBge3J9DQojIGNyZWF0ZSBhIGZyZXF1ZW5jeSB0YWJsZQ0KZnJlcXRhYmxlIDwtIHRhYmxlKG1wZyRtYW51ZmFjdHVyZXIpDQpkZiA8LSBhcy5kYXRhLmZyYW1lLnRhYmxlKGZyZXF0YWJsZSkNCmhlYWQoZGYpDQpgYGANCg0KYGBge3J9DQpnZ3Bsb3QoZGYsIGFlcyhWYXIxLCBGcmVxKSkgKyANCiAgZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiLCB3aWR0aCA9IDAuNSwgZmlsbD0idG9tYXRvMiIpICsgDQogIGxhYnModGl0bGU9IkJhciBDaGFydCIsIA0KICAgICAgIHN1YnRpdGxlPSJNYW51ZmFjdHVyZXIgb2YgdmVoaWNsZXMiLCANCiAgICAgICBjYXB0aW9uPSJTb3VyY2U6IEZyZXF1ZW5jeSBvZiBNYW51ZmFjdHVyZXJzIGZyb20gJ21wZycgZGF0YXNldCIsDQogICAgICAgeCA9ICJNYW51ZmFjdHVyZXIiKSArDQogIHRoZW1lX2NsYXNzaWMoKSArDQogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlPTY1LCB2anVzdD0wLjYpKSAgIyB0byBnaXZlIHggbGFiZWxzIGFuIGFuZ2xlIGZvciByZWFkYWJpbGl0eSANCmBgYA0KDQoqKkVtYWlsIENhbXBhaWduIEZ1bm5lbCoqIGZyb20gW1RvcCA1MCBnZ3Bsb3QyIFZpc3VhbGl6YXRpb25zXShodHRwOi8vci1zdGF0aXN0aWNzLmNvL1RvcDUwLUdncGxvdDItVmlzdWFsaXphdGlvbnMtTWFzdGVyTGlzdC1SLUNvZGUuaHRtbCk6DQoNCmBgYHtyfQ0Kb3B0aW9ucyhzY2lwZW4gPSA5OTkpICAjIHR1cm5zIG9mZiBzY2llbnRpZmljIG5vdGF0aW9ucyBsaWtlIDFlKzQwDQpvcHRpb25zKHJlcHIucGxvdC53aWR0aD03LCByZXByLnBsb3QuaGVpZ2h0PTUpICAjIE1vZGlmeWluZyB0aGUgY2hhcnQgc2l6ZQ0KDQojIFJlYWQgZGF0YQ0Kb3B0aW9ucyhyZWFkci5udW1fY29sdW1ucyA9IDApICAjIHR1cm5zIG9mZiBtZXNzYWdlcyBwcmludGVkIGJ5IHJlYWRfY3N2DQplbWFpbF9jYW1wYWlnbl9mdW5uZWwgPC0gcmVhZF9jc3YoImh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9zZWx2YTg2L2RhdGFzZXRzL21hc3Rlci9lbWFpbF9jYW1wYWlnbl9mdW5uZWwuY3N2IikNCg0KIyBYIEF4aXMgQnJlYWtzIGFuZCBMYWJlbHMgDQpicmtzIDwtIHNlcSgtMTUwMDAwMDAsIDE1MDAwMDAwLCA1MDAwMDAwKQ0KbGJscyA9IHBhc3RlMChhcy5jaGFyYWN0ZXIoYyhzZXEoMTUsIDAsIC01KSwgc2VxKDUsIDE1LCA1KSkpLCAibSIpDQoNCiMgUGxvdA0KZ2dwbG90KGVtYWlsX2NhbXBhaWduX2Z1bm5lbCwgYWVzKHggPSBTdGFnZSwgeSA9IFVzZXJzLCBmaWxsID0gR2VuZGVyKSkgKyAgICMgRmlsbCBjb2x1bW4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCB3aWR0aCA9IC42KSArICAgIyBkcmF3IHRoZSBiYXJzDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzID0gYnJrcywgICAjIEJyZWFrcw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGxibHMpICsgIyBMYWJlbHMNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvb3JkX2ZsaXAoKSArICAjIEZsaXAgYXhlcw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFicyh0aXRsZSA9ICJFbWFpbCBDYW1wYWlnbiBGdW5uZWwiKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGVtZV90dWZ0ZSgpICsgICMgVHVmdGUgdGhlbWUgZnJvbSBnZ2ZvcnRpZnkNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAuNSksIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYXhpcy50aWNrcyA9IGVsZW1lbnRfYmxhbmsoKSkgICMgQ2VudHJlIHBsb3QgdGl0bGUNCmBgYA0KDQojIyMgTGluZSBjaGFydA0KYGBge3J9DQpkdGVtcCA8LSBkYXRhLmZyYW1lKG1vbnRocyA9IGZhY3RvcihyZXAoc3Vic3RyKG1vbnRoLm5hbWUsMSwzKSwgNCksIGxldmVscyA9IHN1YnN0cihtb250aC5uYW1lLDEsMykpLA0KICAgICAgICAgICAgICAgICAgICBjaXR5ID0gcmVwKGMoIlRva3lvIiwgIk5ldyBZb3JrIiwgIkJlcmxpbiIsICJMb25kb24iKSwgZWFjaCA9IDEyKSwNCiAgICAgICAgICAgICAgICAgICAgdGVtcCA9IGMoNy4wLCA2LjksIDkuNSwgMTQuNSwgMTguMiwgMjEuNSwgMjUuMiwgMjYuNSwgMjMuMywgMTguMywgMTMuOSwgOS42LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAtMC4yLCAwLjgsIDUuNywgMTEuMywgMTcuMCwgMjIuMCwgMjQuOCwgMjQuMSwgMjAuMSwgMTQuMSwgOC42LCAyLjUsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIC0wLjksIDAuNiwgMy41LCA4LjQsIDEzLjUsIDE3LjAsIDE4LjYsIDE3LjksIDE0LjMsIDkuMCwgMy45LCAxLjAsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIDMuOSwgNC4yLCA1LjcsIDguNSwgMTEuOSwgMTUuMiwgMTcuMCwgMTYuNiwgMTQuMiwgMTAuMywgNi42LCA0LjgpKQ0KDQp0ZW1wIDwtIGdncGxvdChkdGVtcCwgYWVzKHggPSBtb250aHMsIHkgPSB0ZW1wLCBncm91cCA9IGNpdHksIGNvbG9yID0gY2l0eSkpICsNCiAgZ2VvbV9saW5lKCkgKyANCiAgZ2VvbV9wb2ludChzaXplID0gMS4xKSArIA0KICBnZ3RpdGxlKCJNb250aGx5IEF2ZXJhZ2UgVGVtcGVyYXR1cmUiKSArDQogIHRoZW1lX2hjKHN0eWxlID0gImRhcmt1bmljYSIpICsNCiAgc2NhbGVfZmlsbF9oYygiZGFya3VuaWNhIikNCnRlbXANCmBgYA0KDQojIEludGVyYWN0aXZlIHBsb3R0aW5nIHdpdGggUGxvdGx5DQpXZSBjYW4gdXNlIHBhY2thZ2UgKipwbG90bHkqKiBvbiB0b3Agb2YgYSBnZ3Bsb3QgcGxvdCB0byBjcmVhdGUgaW50ZXJhY3RpdmUgY2hhcnRzLiBQbG90bHkgaXMgYSBwb3dlcmZ1bCB0b29sIGZvciBjcmVhdGluZyBpbnRlcmFjdGl2ZSBkYXNoYm9hcmRzIGFuZCBwbG90cyBhbmQgdGhlcmUgYXJlIGRpZmZlcmVudCB3YXlzIHRvIHVzZSBpdC4gSGVyZSB3ZSB3aWxsIG9ubHkgc2hvdyBob3cgdG8gbWFrZSBnZ3Bsb3RzIGludG8gYSBwbG90bHkgYnkgdXNpbmcgYGdncGxvdGx5KClgIGZ1bmN0aW9uLiBGb3IgbW9yZSBpbmZvcm1hdGlvbiBhYm91dCBvdGhlciB3YXlzIHRvIGxldmVyYWdlIHRoaXMgcGFja2FnZSBnbyB0byBbcGxveS5seV0oaHR0cHM6Ly9wbG90Lmx5LykuDQoNCiMjIFNjYXR0ZXJwbG90DQpMZXQncyB1c2UgdGhlIG1vc3QgcmVjZW50IHBsb3Qgd2UgY3JlYXRlZCB3aXRoIFdTSiB0aGVtZSBhcyBhbiBleGFtcGxlOg0KDQpgYGB7ciB3YXJuaW5nPUZBTFNFfQ0KZ2dwbG90bHkocDIgKyB0aGVtZV93c2ooKSArIHNjYWxlX2NvbG91cl93c2ooImNvbG9yczYiLCAiIikpICAjIFNhbWUgcGxvdCB3aXRoIGdncGxvdGx5KCkNCmBgYA0KDQojIyBUaW1lIFNlcmllcw0KVXNpbmcgYGdlb21fbGluZSgpYCwgYSB0aW1lIHNlcmllcyAob3IgbGluZSBjaGFydCkgY2FuIGJlIGRyYXduLiBEYXRhOiBgZWNvbm9taWNzYCBmcm9tIGdncGxvdDIuDQoNCmBgYHtyfQ0KaGVhZChlY29ub21pY3MpDQpgYGANCg0KDQpgYGB7cn0NCnRzX3Bsb3QgPC0gZ2dwbG90KGVjb25vbWljcywgYWVzKHg9ZGF0ZSkpICsgDQpnZW9tX2xpbmUoYWVzKHk9cHNhdmVydCkpICsgDQogIGxhYnModGl0bGU9IlVTIGVjb25vbWljIHRpbWUgc2VyaWVzIiwgDQogICAgICAgc3VidGl0bGUgPSAiUGVyc29uYWwgU2F2aW5ncyBSYXRlIiwNCiAgICAgICBjYXB0aW9uPSJTb3VyY2U6IEVjb25vbWljcyIsIA0KICAgICAgIHk9IlNhdmluZ3MgUmF0ZSAlIikgKw0KICB0aGVtZV9jbGFzc2ljKCkNCg0KZ2dwbG90bHkodHNfcGxvdCkgICMgU2FtZSBwbG90IHdpdGggZ2dwbG90bHkoKQ0KYGBgDQoNCiMjIEJhciBjaGFydA0KDQpgYGB7ciB3YXJuaW5nPUZBTFNFfQ0KYmFyX3Bsb3QgPC0gZ2dwbG90KGRhdGEgPSBkaWFtb25kcykgKyANCiAgZ2VvbV9iYXIobWFwcGluZyA9IGFlcyh4ID0gY3V0LCBmaWxsID0gY2xhcml0eSksIHBvc2l0aW9uID0gImRvZGdlIikgKw0KICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCIjNDFmNGY0IiwgIiM0MWQ5ZjQiLCAiIzQxYmJmNCIsICIjNDE4ZWY0IiwgIiM0MTVlZjQiLCAiIzZhNDFmNCIsICIjOTc0MWY0IiwgIiNmNDQxZjEiKSkNCg0KZ2dwbG90bHkoYmFyX3Bsb3QpICAjIFNhbWUgcGxvdCB3aXRoIGdncGxvdGx5KCkNCmBgYA0KDQotLS0tDQoNCiMgQWRkaXRpb25hbCBSZWNvdXJzZXMNCiogRXhhbXBsZXMgb2YgZWxhYm9yYXRlIGNoYXJ0czogW1RvcCA1MCBnZ3Bsb3QyIFZpc3VhbGl6YXRpb25zXShodHRwOi8vci1zdGF0aXN0aWNzLmNvL1RvcDUwLUdncGxvdDItVmlzdWFsaXphdGlvbnMtTWFzdGVyTGlzdC1SLUNvZGUuaHRtbCkNCiogVG8gZ28gYmV5b25kIGdncGxvdDIgZnVuY3Rpb25hbGl0aWVzIGNoZWNrIG91dCB0aGVzZSBleHRlbnNpb25zOiBbZ2dwbG90MiBleHRlbnNpb25zXShodHRwOi8vd3d3LmdncGxvdDItZXh0cy5vcmcvZ2FsbGVyeS8pDQoqICpnZ3Bsb3QyLWNoZWF0c2hlZXQucGRmKiBpbiB0aGUgY2hlYXRzaGVldHMgZGlyZWN0b3J5DQoqIEhleCBjb2xvcg0KICAgICogU2ltcGx5IGdvb2dsZSAiaGV4IGNvbG9yIHBpY2tlciIgYW5kIHVzZSBHb29nbGUncyB0b29sDQoqIFRoZW1lcw0KICAgICogW2dndGhlbWVzXShodHRwczovL2dpdGh1Yi5jb20vanJub2xkL2dndGhlbWVzKSAtIEV4YW1wbGVzIFtoZXJlXShodHRwczovL21yYW4ubWljcm9zb2Z0LmNvbS9zbmFwc2hvdC8yMDE2LTEyLTAzL3dlYi9wYWNrYWdlcy9nZ3RoZW1lcy92aWduZXR0ZXMvZ2d0aGVtZXMuaHRtbCkNCiAgICAqIFtnZ3RlY2hdKGh0dHBzOi8vZ2l0aHViLmNvbS9yaWNhcmRvLWJpb24vZ2d0ZWNoKQ0K